use crate::chess::*;
use ahash::AHashMap;

// 对战过程
pub struct Session {
    pub book: Book,
    pub board: Board,
    // 轮哪一方走
    pub turn: Color,
    // 是否在叫将，以及将(帅)的位置
    pub killing: Option<Pos>,
    // 是否绝杀
    pub finished: bool,
    // 当前的局面
    pub current_situation: SituationId,

    dict: AHashMap<[u8; 90], SituationId>,

    pub steps: Vec<(SituationId, Pos, Pos, Option<(Color, Piece)>)>,

    pub book_changed: bool,
}

impl Session {
    pub fn new(book: Book, start: Option<SituationId>, turn: Option<Color>) -> Self {
        let (start, turn) = (start.unwrap_or(book.start), turn.unwrap_or(book.turn));
        let board = book.create_board(start);
        let dict = book.build_dict();
        Self {
            book,
            board,
            dict,
            turn,
            killing: None,
            finished: false,
            current_situation: start,
            steps: Vec::with_capacity(200),
            book_changed: false,
        }
    }

    // 尝试走棋
    pub fn try_move(&mut self, from: Pos, to: Pos) -> bool {
        // 尝试走棋
        let (sucess, eaten_piece) = self.board.try_move(self.turn, from, to);
        if sucess {
            // 走棋成功
            self.turn = self.turn.opponent();
            self.check_board_status();
            self.steps
                .push((self.current_situation, from, to, eaten_piece));

            // 更新棋谱
            let next_situation = self.book.find_or_add_situation(&mut self.dict, &self.board);
            if self
                .book
                .add_step(self.current_situation, next_situation, from, to)
            {
                self.book_changed = true;
            }
            self.current_situation = next_situation;
        }
        sucess
    }

    pub fn check_board_status(&mut self) {
        let player = self.turn;
        // 判断是否“困毙”
        if self.board.is_trapped(player) {
            self.finished = true;
        }
        // 判断是否“将军”
        self.killing = self.board.check_killing(player);
        if self.killing.is_some() {
            // 判断是否“绝杀”
            if self.board.is_killed(player) {
                self.finished = true;
            }
        }
    }

    pub fn last_step(&self) -> Option<(SituationId, Pos, Pos, Option<(Color, Piece)>)> {
        if self.steps.len() > 0 {
            Some(self.steps[self.steps.len() - 1])
        } else {
            None
        }
    }

    // 下一步的走法
    pub fn get_next_steps(&self) -> Vec<Step> {
        self.book.get_next_steps(self.current_situation, self.turn)
    }

    // 跳转到开局
    pub fn goto_start(&mut self) {
        self.steps.clear();
        self.board = self.book.create_board(self.book.start);
        self.turn = self.book.turn;
        self.killing = None;
        self.finished = false;
        self.current_situation = self.book.start;
    }

    // 跳转到上一步
    pub fn goto_prev_step(&mut self) {
        if let Some((prev, from, to, eaten)) = self.steps.pop() {
            self.board.revert_move(from, to, eaten);
            self.turn = self.turn.opponent();
            self.killing = self.board.check_killing(self.turn);
            self.finished = false;
            self.current_situation = prev;
        }
    }

    // 跳转到下一步
    pub fn goto_next_step(&mut self) {
        let next_steps = self.get_next_steps();
        if next_steps.len() >= 1 {
            self.enter_step(&next_steps[0]);
        }
    }

    // 跳转到下一分支
    pub fn goto_next_branch(&mut self) {
        loop {
            let next_steps = self.get_next_steps();
            if next_steps.len() == 1 {
                self.enter_step(&next_steps[0]);
            } else {
                break;
            }
        }
    }

    // 跳转到所选分支
    pub fn enter_branch(&mut self, index: usize) {
        let next_steps = self.get_next_steps();
        if next_steps.len() > 0 && index < next_steps.len() {
            self.enter_step(&next_steps[index]);
        }
    }

    fn enter_step(&mut self, step: &Step) {
        let eaten_piece = self.board.apply_move(step.from, step.to);
        self.turn = self.turn.opponent();
        self.check_board_status();
        self.steps
            .push((self.current_situation, step.from, step.to, eaten_piece));
        self.current_situation = step.next;
    }

    // 给走法评分
    pub fn set_score(&mut self, from: Pos, to: Pos, score: u8) {
        if let Some(situation) = self.book.get_situation_mut(self.current_situation) {
            situation.set_score(from, to, score);
            self.book_changed = true;
        }
    }

    // 删除走法
    pub fn delete_step(&mut self, from: Pos, to: Pos) {
        if self.book.delete_step(self.current_situation, from, to) {
            self.book_changed = true;
        }
    }

    // 导入棋谱
    pub fn import_book(&mut self, other: &Book) {
        if self.book.import_book(&mut self.dict, other) {
            self.book_changed = true;
        }
    }

    // 跳转到指定的局面
    pub fn goto_situation(&mut self, id: SituationId, turn: Color) {
        self.current_situation = id;
        self.turn = turn;
        self.board = self.book.create_board(id);
        self.killing = self.board.check_killing(self.turn);
        self.finished = false;
        while let Some((situation_id, _, _, _)) = self.steps.pop() {
            if situation_id == id {
                break;
            }
        }
    }
}
